#include "udpServer.hpp"
#include "onlineUser.hpp"
#include <memory>
#include <unordered_map>
#include <string>
#include <fstream>
#include <signal.h>

using namespace Server;
using namespace std;

const string dictTxt = "./dict.txt"; // 配置文件
unordered_map<string, string> dict;

// ./udpServer port
void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n"
         << endl;
}

// 业务逻辑和络通网逻信辑解耦

// 切割子串
static bool cutString(const string &target, string *key, string *value, const string &sep)
{
    auto pos = target.find(sep);
    if (pos == string::npos)
    {
        return false;
    }
    *key = target.substr(0, pos);
    *value = target.substr(pos + sep.size());
    return true;
}

static void initDict()
{
    ifstream in(dictTxt, std::ios::binary); // 以二进制方式打开文件流
    if (!in.is_open())
    {
        cerr << "open file " << dictTxt << " error" << endl;
        exit(OPEN_ERR);
    }
    string line;
    string key;
    string value;
    while (getline(in, line))
    {
        // cout << line << endl; //测试
        if (cutString(line, &key, &value, ":"))
        {
            dict.insert(make_pair(key, value));
        }
    }
    in.close();
    cout << "load dict success" << endl;
}
// 热加载，不用重启服务器就可以加载配置文件
static void reolad(int signo)
{
    (void)signo;
    initDict();
}
// 测试切割
static void debugPrint()
{
    for (auto &dt : dict)
    {
        cout << dt.first << " # " << dt.second << endl;
    }
}
// demo1 翻译
void handleMessage(int sockfd, const string &clientip, const uint16_t &clientport, const string &message)
{
    string respon_message;
    auto iter = dict.find(message);
    if (iter == dict.end())
    {
        respon_message = "unknow";
    }
    else
    {
        respon_message = iter->second;
    }

    // 开始返回
    sockaddr_in client;
    socklen_t len = sizeof(client);
    bzero(&client, 0);
    client.sin_family = AF_INET;
    client.sin_port = htons(clientport);
    client.sin_addr.s_addr = inet_addr(clientip.c_str());
    sendto(sockfd, respon_message.c_str(), respon_message.size(), 0, (sockaddr *)&client, len);
}

// demo2 执行指令

void execCommond(int sockfd, const string &clientip, const uint16_t &clientport, const string &command)
{
    string respon_message;
    FILE *pipe = popen(command.c_str(), "r"); // 执行命令
    if (pipe == nullptr)
    {
        respon_message = command + " exec failed";
    }
    char line[1024];
    while (fgets(line, sizeof(line), pipe)) // 收集命令结果输出
    {
        respon_message += line;
    }
    pclose(pipe);

    // 开始返回
    struct sockaddr_in client;
    bzero(&client, 0);
    socklen_t len = sizeof(client);
    client.sin_family = AF_INET;
    client.sin_port = htons(clientport);
    client.sin_addr.s_addr = inet_addr(clientip.c_str());
    sendto(sockfd, respon_message.c_str(), respon_message.size(), 0, (struct sockaddr *)&client, len);
}

// demo3 多人聊天
OnlineUser onlineuser;
void routeMessage(int sockfd, const string &clientip, const uint16_t &clientport, const string &message)
{
    // 上线
    if (message == "online")
    {
        onlineuser.addUser(clientip, clientport);
    }
    // 下线
    if (message == "offline")
    {
        onlineuser.delUser(clientip, clientport);
    }
    // 判断用户是否在线
    if (onlineuser.isonline(clientip, clientport))
    {
        // 给所有在线用户广播信息
        onlineuser.boardcastMessage(sockfd, clientip, clientport, message);
    }
    // 如果不在线，单独发信息提醒用户上线
    else
    {
        string respon_message="你还未上线，请先上线，运行：online";
        struct sockaddr_in client;
        bzero(&client, 0);
        socklen_t len = sizeof(client);
        client.sin_family = AF_INET;
        client.sin_port = htons(clientport);
        client.sin_addr.s_addr = inet_addr(clientip.c_str());
        sendto(sockfd, respon_message.c_str(), respon_message.size(), 0, (struct sockaddr *)&client, len);
    }
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    signal(2, reolad);

    // initDict();
    // debugPrint();
    unique_ptr<udpServer> usvr(new udpServer(routeMessage, port));
    usvr->InitServer();
    usvr->Start();
    return 0;
}